package com.gopay.bis.pab.expay.rsa;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.io.IOUtils;
import org.apache.xml.security.Init;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.sun.security.sasl.Provider;

public class XmlSignatureHelper {
	
	private static KeyStore keyStore;
	
	public XmlSignatureHelper(String cafile,String store_password)
	  {
	    Init.init();
	    
	    Security.addProvider(new Provider());
	    InputStream inputStream = null;
	    try
	    {
	      inputStream = new FileInputStream(cafile);
	    } catch (FileNotFoundException e) {
	      e.printStackTrace();
	    }
	    char[] pass = store_password != null ? store_password.toCharArray() : null;
	    try
	    {
	      keyStore = KeyStore.getInstance("PKCS12");
	      keyStore.load(inputStream, pass);
	    } catch (Exception e) {
	      e.printStackTrace();
	    } finally {
	    	if (null != inputStream) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	  }
	
	
	public String sign(String xmlPlain, String plainTagId, PrivateKey privateKey)
		    throws Exception
		  {
		    Document doc = String2Doc(xmlPlain);
		    XMLSignature sign = new XMLSignature(doc, "", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");

		    sign.getSignedInfo().addResourceResolver(new OfflineResolver());

		    Node messageNode = doc.getElementsByTagName("Message").item(0);
		    messageNode.appendChild(sign.getElement());

		    Transforms transforms = new Transforms(doc);
		    transforms.addTransform("http://www.w3.org/2000/09/xmldsig#enveloped-signature");

		    sign.addDocument("#" + plainTagId, transforms, "http://www.w3.org/2000/09/xmldsig#sha1");

		    sign.sign(privateKey);

		    ByteArrayOutputStream os = new ByteArrayOutputStream();
		    XMLUtils.outputDOM(doc, os);

		    return os.toString("utf-8");
		  }
	
	public boolean verify(String xml, PublicKey pubKey) throws Exception {
		Document doc = String2Doc(xml);

		Element nscontext = XMLUtils.createDSctx(doc, "ds",
				"http://www.w3.org/2000/09/xmldsig#");

		Element signElement = (Element) XPathAPI.selectSingleNode(doc,
				"//ds:Signature[1]", nscontext);

		if (signElement == null) {
			return false;
		}

		XMLSignature signature = new XMLSignature(signElement, "");

		return signature.checkSignatureValue(pubKey);
	}
	
	private  PrivateKey getPrivateKey(InputStream priKeyName,String keyStorePsw,String priKeyPassword){
    	PrivateKey priv=null;
		try {
			KeyStore ks = KeyStore.getInstance("PKCS12");
			ks.load(priKeyName, keyStorePsw.toCharArray());
			
			Enumeration en = ks.aliases();
			
			String alias = null;
			for (int i = 0; en.hasMoreElements(); i++) {
				alias = en.nextElement().toString();
				if (i >= 1) {
					System.out.println("���ļ��к��ж��֤��!");
				}
			}
			priv = (PrivateKey) ks.getKey(alias,priKeyPassword.toCharArray());
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
    	return priv;
    }
    
    private  PublicKey getPublicKey(InputStream pubKeyName){
    	PublicKey pub=null;
		try {
			CertificateFactory certificatefactory =	CertificateFactory.getInstance("X.509");
			X509Certificate certificate = (X509Certificate)certificatefactory.generateCertificate(pubKeyName);
			pub = certificate.getPublicKey();
		} catch (CertificateException e) {
			e.printStackTrace();
		}
    	return pub;
    }
	
	 private Document String2Doc(String xml) throws Exception
	  {
	    InputStream is = IOUtils.toInputStream(xml, "UTF-8");
	    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
	    docBuilderFactory.setNamespaceAware(true);
	    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
	    return docBuilder.parse(is);
	  }
}
